// Learn cc.Class:
//  - https://docs.cocos.com/creator/manual/en/scripting/class.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html
let MultiTextureAssembler = require('MultiTextureAssembler');
let MultiLayer = require('MultiLayer');


var MultiSprite = cc.Class({
    extends: cc.RenderComponent,
    mixins: [cc.BlendFunc],


    properties: {

        _spriteFrame: {
            default: null,
            type: cc.SpriteFrame
        },

        _textureIdx: {
            default: 0,
            type: cc.Integer,
        },
        _sizeMode: cc.Sprite.SizeMode.TRIMMED,
        _atlas: {
            default: null,
            type: cc.SpriteAtlas,
            tooltip: CC_DEV && 'i18n:COMPONENT.sprite.atlas',
            editorOnly: true,
            visible: true,
            animatable: false
        },
        _isTrimmedMode: true,
        spriteFrame: {
            get () {
                return this._spriteFrame;
            },
            set (value, force) {
                var lastSprite = this._spriteFrame;
                if (CC_EDITOR) {
                    if (!force && ((lastSprite && lastSprite._uuid) === (value && value._uuid))) {
                        return;
                    }
                }
                else {
                    if (lastSprite === value) {
                        return;
                    }
                }
                this._spriteFrame = value;
                this._applySpriteFrame(lastSprite);
                if (CC_EDITOR) {
                    this.node.emit('spriteframe-changed', this);
                }
            },
            type: cc.SpriteFrame,
        },


        textureIdx: {
            get () {
                return this._textureIdx;
            },
            set (value) {
                if (this._type !== value) {
                    this._textureIdx = value;
                    this.FlushProperties();
                }
            },
            animatable: false,
            type: cc.Float,
        },

        sizeMode: {
            get () {
                return this._sizeMode;
            },
            set (value) {
                this._sizeMode = value;
                if (value !== cc.Sprite.SizeMode.CUSTOM) {
                    this._applySpriteSize();
                }
            },
            animatable: false,
            type: cc.Sprite.SizeMode,
            tooltip: CC_DEV && 'i18n:COMPONENT.sprite.size_mode'
        },

        trim: {
            get () {
                return this._isTrimmedMode;
            },
            set (value) {
                if (this._isTrimmedMode !== value) {
                    this._isTrimmedMode = value;
                    this.setVertsDirty();
                }
            },
            animatable: false,
            tooltip: CC_DEV && 'i18n:COMPONENT.sprite.trim'
        },
        multi:MultiLayer,

    },


    onEnable () {
        this._super();
        this._spriteFrame && this._spriteFrame.ensureLoadTexture();

        this.node.on(cc.Node.EventType.SIZE_CHANGED, this.setVertsDirty, this);
        this.node.on(cc.Node.EventType.ANCHOR_CHANGED, this.setVertsDirty, this);
    },

    onDisable () {
        this._super();
        
        this.node.off(cc.Node.EventType.SIZE_CHANGED, this.setVertsDirty, this);
        this.node.off(cc.Node.EventType.ANCHOR_CHANGED, this.setVertsDirty, this);
    },


    __preload () {
        this._super();
        this._applySpriteFrame();
    },

    _validateRender () {
        let spriteFrame = this._spriteFrame;
        if (this._materials[0] &&
            spriteFrame && 
            spriteFrame.textureLoaded()) {
            return;
        }

        this.disableRender();
    },


    _applySpriteFrame (oldFrame) {
        let oldTexture = oldFrame && oldFrame.getTexture();
        if (oldTexture && !oldTexture.loaded) {
            oldFrame.off('load', this._applySpriteSize, this);
        }

        this._updateMaterial();
        let spriteFrame = this._spriteFrame;
        if (spriteFrame) {
            let newTexture = spriteFrame.getTexture();
            if (newTexture && newTexture.loaded) {
                this._applySpriteSize();
            }
            else {
                this.disableRender();
                spriteFrame.once('load', this._applySpriteSize, this);
            }
        }
        else {
            this.disableRender();
        }

        if (CC_EDITOR) {
            // Set atlas
            this._applyAtlas(spriteFrame);
        }
    },

    _applyAtlas: CC_EDITOR && function (spriteFrame) {
        // Set atlas
        if (spriteFrame && spriteFrame._atlasUuid) {
            var self = this;
            cc.assetManager.loadAny(spriteFrame._atlasUuid, function (err, asset) {
                self._atlas = asset;
            });
        } else {
            this._atlas = null;
        }
    },

    _applySpriteSize () {
        if (!this._spriteFrame || !this.isValid)  return;
        
        if (cc.Sprite.SizeMode.RAW === this._sizeMode) {
            var size = this._spriteFrame._originalSize;
            this.node.setContentSize(size);
        } else if (cc.Sprite.SizeMode.TRIMMED === this._sizeMode) {
            var rect = this._spriteFrame._rect;
            this.node.setContentSize(rect.width, rect.height);
        }
        
        this.setVertsDirty();
    },


    FlushProperties() {
        //@ts-ignore
        let assembler=this._assembler;
        if (!assembler)
            return;

        assembler.texture_idx = this._textureIdx;
        this.setVertsDirty();
    },
    _resetAssembler() {
        this.setVertsDirty();
        let assembler = this._assembler = new MultiTextureAssembler();

        this.FlushProperties();
        assembler.init(this);

        this._updateColor(); 

    },

    _updateMaterial () {
        let texture = this._spriteFrame && this._spriteFrame.getTexture();
        
        // make sure material is belong to self.
        let material = this.getMaterial(0);
        if (material) {
            if (material.getDefine('USE_TEXTURE') !== undefined) {
                material.define('USE_TEXTURE', true);
            }
            if(cc.isValid(this.multi)){
                    this.multi.addTexture(texture,material,this)
                    this.multi.addMaterial(material,this)
            }else{
                material.setProperty('texture0', texture);
                this.textureIdx = 0
               
            }
        }
        cc.BlendFunc.prototype._updateMaterial.call(this);
    },


    // update (dt) {},
});

if (CC_EDITOR) {
    MultiSprite.prototype._resizedInEditor = function () {
        if (this._spriteFrame) {
            var actualSize = this.node.getContentSize();
            var expectedW = actualSize.width;
            var expectedH = actualSize.height;
            if (this._sizeMode === SizeMode.RAW) {
                var size = this._spriteFrame.getOriginalSize();
                expectedW = size.width;
                expectedH = size.height;
            } else if (this._sizeMode === SizeMode.TRIMMED) {
                var rect = this._spriteFrame.getRect();
                expectedW = rect.width;
                expectedH = rect.height;

            }

            if (expectedW !== actualSize.width || expectedH !== actualSize.height) {
                this._sizeMode = SizeMode.CUSTOM;
            }
        }
    };

    // override onDestroy
    MultiSprite.prototype.__superOnDestroy = cc.Component.prototype.onDestroy;
    MultiSprite.prototype.onDestroy = function () {
        if (this.__superOnDestroy) this.__superOnDestroy();
        this.node.off(cc.Node.EventType.SIZE_CHANGED, this._resizedInEditor, this);
    };
}


cc.MultiSprite = module.exports = MultiSprite;



